import ReactDOM from 'react-dom'

// 1. useState简单实现
// 记录当前是第几次 useState 调用
let hookIndex = 0
// hookState 变量的作用：存储最新的状态值
let hookState = []

const useState = (initialValue) => {
  // 只需要在 useState 内部，创建一个 currentIndex 变量，就可以解决索引的问题
  // 使用 闭包 来存储每次调用 useState 时，自己的索引
  let currentIndex = hookIndex

  // 判断 hookState 是否有值，如果没有就使用 initialValue；否则，就直接返回 hookState
  hookState[currentIndex] = hookState[currentIndex] || initialValue
  // 更新状态的函数
  const setState = (newValue) => {
    // hookState[hookIndex] = newValue
    hookState[currentIndex] = newValue
    // 通知 React 重新渲染 App 组件
    render()
  }

  // 每次调用 useState，最后，都让 索引 +1
  const ret = [hookState[currentIndex], setState]
  hookIndex++
  return ret
}

// 为了能够让我们自己写的 useState 能够实现组件重新渲染
// 此处，我们借用 ReactDOM.render() 方法，来重新渲染组件
function render() {
  // 注意：useState hook 的调用顺序，从调用 useState 时，就定下来了
  //      不管组件怎么更新，每次调用 useState hook 的顺序不能变
  //      因此，在每次组件更新后，都将 hookIndex 的顺序重置为 0
  hookIndex = 0

  ReactDOM.render(<App />, document.getElementById('root'))
}

// 2. useEffect简单实现
const useEffect = (callback, deps) => {
  // 获取上一次的依赖
  const lastDeps = hookState[hookIndex]

  // 记录有没有依赖项
  let hasNoDeps = false
  // 记录依赖项是否发生改变
  let hasDepsChanged = false
  // 判断有没有依赖项
  if (!deps) {
    // 没有依赖项
    hasNoDeps = true
  } else {
    // 前提：只要代码执行到这，说明是有依赖项的
    // 如果上一次的依赖项为空，说明是第一次执行 useEffect
    // 此时，不管 useEffect 的依赖项时什么，都必须要执行一次 回调函数
    if (!lastDeps) {
      hasDepsChanged = true
    } else {
      // 有依赖项
      // 通过 some 方法的返回值来表示依赖项是否发生改变
      // 约定：返回 true 表示发生了变化；返回 false 表示没有发生变化
      hasDepsChanged = deps.some((item, index) => {
        return item !== lastDeps[index]
      })
    }
  }

  if (hasNoDeps || hasDepsChanged) {
    callback()
    // 将最新的依赖项保存到 state 变量中
    hookState[hookIndex] = deps
  }

  hookIndex++
}

// 测试
export default function App() {
  // debugger
  const [count, setCount] = useState(0) // 对应的索引为：0
  const [age, setAge] = useState(18) //    对应的索引为：1
  const [name, setName] = useState(100) //    对应的索引为：2

  // console.log('App 组件重新渲染了', count, age)
  console.log('两次调用结束后 hookIndex：', hookIndex, hookState)

  // useEffect(() => {
  //   console.log('每次都会执行')
  // })
  // useEffect(() => {
  //   console.log('只会执行一次')
  // }, [])

  // useEffect(() => {
  //   console.log('age 改变时会执行')
  // }, [age])

  return (
    <div style={{ backgroundColor: '#ccc', padding: 20 }}>
      <h1>计数器0：{count}</h1>
      <button onClick={() => setCount(count + 1)}>+1</button>

      <hr />
      <p>计数器1：{age}</p>
      <button onClick={() => setAge(age + 10)}>+10</button>

      <hr />
      <p>计算器2：{name}</p>
      <button onClick={() => setName(Math.random())}>random</button>
    </div>
  )
}
